﻿using ServiceStack.Redis;
using StackExchange.Redis;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace Publicuse.Util.Redis
{
    public class RedisTools
    {
        /// <summary>
        /// 将实体对象放入HashEntry
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="hResult"></param>
        /// <returns></returns>
        public static bool ObjectToHashEntrys(object obj, out HashEntry[] hResult)
        {
            hResult = null;

            if (null == obj)
                return false;

            try
            {
                Type ot = obj.GetType();
                PropertyInfo[] propertys = ot.GetProperties();
                hResult = new HashEntry[propertys.Length];

                for (int i = 0; i < propertys.Length; i++)
                    hResult[i] = new HashEntry(propertys[i].Name, propertys[i].GetValue(obj).ToString());
            }
            catch { return false; }

            return true;
        }

        public static bool HashEntrysToObject<T>(HashEntry[] hash, out T oResult)
        {
            Type type = typeof(T);
            oResult = (T)Activator.CreateInstance(type);
            PropertyInfo p;
            foreach (HashEntry h in hash)
            {
                if ((p = type.GetProperty(h.Name)) != null)
                {
                    try
                    {
                        if (p.PropertyType == typeof(string))
                            p.SetValue(oResult, h.Value.ToString());
                        else if (p.PropertyType == typeof(short))
                            p.SetValue(oResult, Convert.ToInt16(h.Value.ToString()));
                        else if (p.PropertyType == typeof(int))
                            p.SetValue(oResult, Convert.ToInt32(h.Value.ToString()));
                        else if (p.PropertyType == typeof(float))
                            p.SetValue(oResult, Convert.ToSingle(h.Value.ToString()));
                        else if (p.PropertyType == typeof(double))
                            p.SetValue(oResult, Convert.ToDouble(h.Value.ToString()));
                        else if (p.PropertyType == typeof(bool))
                            p.SetValue(oResult, Convert.ToBoolean(h.Value.ToString()));
                        else if (p.PropertyType == typeof(byte))
                            p.SetValue(oResult, Convert.ToByte(h.Value.ToString()));
                        else if (p.PropertyType == typeof(decimal))
                            p.SetValue(oResult, Convert.ToDecimal(h.Value.ToString()));
                    }
                    catch { }
                }
            }
            return true;
        }

        public static bool HashEntrysToObject(ref HashEntry[] hash, object oResult)
        {
            Type t = oResult.GetType();
            PropertyInfo p;
            foreach (HashEntry h in hash)
            {
                if ((p = t.GetProperty(h.Name)) != null)
                {
                    try
                    {
                        if (p.PropertyType == typeof(string))
                            p.SetValue(oResult, h.Value.ToString());
                        else if (p.PropertyType == typeof(short))
                            p.SetValue(oResult, Convert.ToInt16(h.Value.ToString()));
                        else if (p.PropertyType == typeof(int))
                            p.SetValue(oResult, Convert.ToInt32(h.Value.ToString()));
                        else if (p.PropertyType == typeof(float))
                            p.SetValue(oResult, Convert.ToSingle(h.Value.ToString()));
                        else if (p.PropertyType == typeof(double))
                            p.SetValue(oResult, Convert.ToDouble(h.Value.ToString()));
                        else if (p.PropertyType == typeof(bool))
                            p.SetValue(oResult, Convert.ToBoolean(h.Value.ToString()));
                        else if (p.PropertyType == typeof(byte))
                            p.SetValue(oResult, Convert.ToByte(h.Value.ToString()));
                        else if (p.PropertyType == typeof(decimal))
                            p.SetValue(oResult, Convert.ToDecimal(h.Value.ToString()));
                    }
                    catch { }
                }
            }
            return true;
        }

        /// <summary>
        /// 获取信息
        /// </summary>
        /// <param name="db"></param>
        /// <param name="prefix"></param>
        /// <param name="key"></param>
        /// <returns></returns>
        public static string GetHashDetail(IDatabase db, string prefix, string key)
        {
            try
            {
                RedisValue val = db.HashGet(prefix, key);
                if (val == RedisValue.Null)
                    return "";
                return val;
            }
            catch (Exception)
            {
                return "";
            }
        }

        /// <summary>
        /// 转换对象为字典集合
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="obj"></param>
        /// <returns></returns>
        public static Dictionary<string, string> ObjectToDictionary<T>(T obj) where T : new()
        {
            Dictionary<string, string> keyValuePairs = new Dictionary<string, string>();
            Type entity = obj.GetType();
            var pros = entity.GetProperties();
            foreach (var item in pros)
            {
                var name = item.Name;
                var value = item.GetValue(obj);
                if (value == null)
                    keyValuePairs.Add(name, "");
                else
                    keyValuePairs.Add(name, value.ToString());
            }
            return keyValuePairs;
        }

        /// <summary>
        /// Redis任务操作
        /// </summary>
        /// <param name="conIndex"></param>
        /// <param name="dbIndex"></param>
        /// <param name="msg"></param>
        /// <param name="action"></param>
        public static void DoAction(int conIndex, int dbIndex, out string msg, Action<IRedisClient> action)
        {
            msg = string.Empty;
            try
            {
                using (var dbClient = ServiceStackManager.GetRedisManager.GetClient(conIndex, dbIndex))
                {
                    action.Invoke(dbClient);
                }
            }
            catch (Exception ex)
            {
                //LogUtil.GetInstance.WriteLogOld("Redis操作", ex.Message + "|" + ex.StackTrace, false);
                msg = ex.Message;
            }
        }
    }
}
